package test.heliotrope.algorithm
{
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.InteractiveObject;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.getTimer;
	
	import heliotrope.display.AutoBitmap;
	import heliotrope.display.RegSprite;
	import heliotrope.global.GlobalEventScheduler;
	import heliotrope.net.loader.CommonLoader;
	import heliotrope.net.loader.LoadMission;
	import heliotrope.net.loader.LoadType;
	import heliotrope.utils.CompassDirection;
	
	import org.hamcrest.object.nullValue;
	
	
	//The attributes of Map must be correct!
	[SWF(frameRate="60")]
	public class DelayedMove_NU extends Sprite
	{
		private static var FACT:Number = 0.382;
		private var _map:RegSprite;
		private var _player:Sprite;
		private var _playerPos:Point;
		private var _aux:RegSprite;
		private var _moveSpeed:uint = 8;
		private var _speedX:Number,_speedY:Number;
		private var _nowDes:Point;
//		private var _resizeNeeders:Array;
		public function DelayedMove_NU()
		{
			//====Please reserve the two lines below====
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			//==========================================
			init();
			
		}
		
		public function init():void
		{
			GlobalEventScheduler.init(this.stage);
			GlobalEventScheduler.getInstance().addResizeListener(resizeHandler);
			initMap();
			initPlayer();
			initAux();			
			addChild(_map);
			addChild(_player);
			addChild(_aux);
			_map.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler);//For better user experience, do not use MOUSE_CLICK
			stage.addEventListener(KeyboardEvent.KEY_DOWN, setPos);
		}
		
		protected function setPos(event:KeyboardEvent):void
		{
			setPlayerPos(8000, 0);
		}
		
		private function setPlayerPos(x_:Number, y_:Number):void
		{
			_playerPos.setTo(x_, y_);
			var tmp:Number = FACT;
			FACT = 0;//Expand fence to full screen.
			move(x_, y_);
			FACT = tmp;
		}
		
		protected function clickHandler(event_:MouseEvent):void
		{
			_nowDes = new Point(event_.localX, event_.localY);
			moveInit();
			GlobalEventScheduler.getInstance().addEnterFrameListener(updateHandler);
//			move(event_.localX, event_.localY);
		}
		

		protected function move(localX_:Number, localY_:Number):void
		{
			var stageWidth:int = stage.stageWidth;
			var stageHeight:int = stage.stageHeight;
			var mapWidth:Number = _map.width;
			var mapHeight:Number = _map.height;
			var fenceLeft:Number = stageWidth*(1-FACT)*0.5;
			var fenceRight:Number = stageWidth*0.5*(1+FACT);
			var fenceTop:Number = stageHeight*(1-FACT)*0.5;
			var fenceBottom:Number = stageHeight*0.5*(1+FACT);
			var localX:Number = localX_;
			var localY:Number = localY_;
			var stagePoint:Point = _map.localToGlobal(new Point(localX, localY));
			
			var resultX:Array = axisCalcu(stagePoint.x, localX, _map.x, mapWidth, stageWidth, _player.x, fenceLeft, fenceRight);
			var resultY:Array = axisCalcu(stagePoint.y, localY, _map.y, mapHeight, stageHeight, _player.y, fenceTop, fenceBottom);
			_player.x = resultX[0];_map.x = resultX[1];
			_player.y = resultY[0];_map.y = resultY[1];
		}
		
		private function axisCalcu(viewCoo_:Number, axisCoo_:Number, axisPos_:Number,
								axisLength_:Number, viewPortSize_:Number, focusPos_:Number,
								fenceLow_:Number, fenceUp_:Number, lowBounds_:Number=0, upBounds_:Number=Number.MAX_VALUE):Array
		{
			lowBounds_ = lowBounds_<0? 0:lowBounds_;
			upBounds_ = upBounds_>axisLength_? axisLength_:upBounds_;
			var innerLength:Number = upBounds_-lowBounds_;
			var horiIn:Boolean = checkInFence(viewCoo_, fenceLow_, fenceUp_);
			var horiBoundLeft:Boolean	= checkInFence(axisCoo_, lowBounds_, lowBounds_+fenceLow_);
			var horiBoundRight:Boolean	= checkInFence(axisCoo_, upBounds_-fenceLow_, upBounds_);
			var result:Array = [];
			result[0] = focusPos_;
			result[1] = axisPos_;
			if(horiIn)
			{
				result[0] = viewCoo_;
			}
			else if(horiBoundLeft)
			{
				result[0] = axisCoo_-lowBounds_;
				result[1] = -lowBounds_;
			}
			else if(horiBoundRight)
			{
				trace("right");
				result[0] = axisCoo_-upBounds_+viewPortSize_;
				result[1] = viewPortSize_-upBounds_;
			}
			else
			{
				var toLeft:Boolean = checkInFence(viewCoo_, 0, viewPortSize_/2);
				var toRight:Boolean = !toLeft;
				if(toLeft)
				{
					result[0] = viewPortSize_-fenceUp_;
				}
				if(toRight)
				{
					result[0] = fenceUp_;
				}
				result[1] = result[0]-axisCoo_;
			}
			return result;
		}
		
		private function checkInFence(target_:Number, left:Number=0, right_:Number=Number.MAX_VALUE):Boolean
		{
			return (target_>=left)&&(target_<=right_);
		}
		
		private function updateHandler(evt:Event):void
		{
			var detaX:Number = Math.abs(_playerPos.x - _nowDes.x);
			var detaY:Number = Math.abs(_playerPos.y - _nowDes.y);
			var flag:int = 0;
			var newX:Number = detaX<=Math.abs(_speedX)?(flag |= 0x1,_nowDes.x) : _playerPos.x+_speedX;
			var newY:Number = detaY<=Math.abs(_speedY)?(flag |= 0x2,_nowDes.y) : _playerPos.y +_speedY;
			
			_playerPos.x = newX;
			_playerPos.y = newY;
			move(newX, newY);
			if(flag == 0x3)
			{
				_nowDes = null;//_walkArray.shift();
				if(!_nowDes)
				{
					GlobalEventScheduler.getInstance().removeEnterFrameListener(updateHandler);
					return;
				}
				moveInit();
			}
		}
		private function moveInit():void
		{
			var distanceX:Number;
			var distanceY:Number;
			var distance:Point = _nowDes.subtract(_playerPos);
			if(distance.length!=0)
			{
				_speedX = _moveSpeed*distance.x/distance.length;
				_speedY = _moveSpeed*distance.y/distance.length;
			}
			else
			{
				_speedX = _speedY = 0;
			}
		}
			
		private function initAux():void
		{
			_aux = new RegSprite(CompassDirection.CENTER);
			var graphic:Graphics = _aux.graphics;
			drawAux(graphic);
			_aux.refresh();
			_aux.mouseChildren = false;
			_aux.mouseEnabled = false;
			setHalfStage(_aux);
		}
		
		private function initMap():void
		{
			_map = new RegSprite();
			var loader:CommonLoader = new CommonLoader;
			var bitMap:AutoBitmap = new AutoBitmap;
			loader.load(new LoadMission(
				"testdata/Graphics/Pictures/MapDe.jpg", bitMap, LoadType.PIC));
			_map.addChild(bitMap);
		}
		
		private function initPlayer():void
		{
			_player = new Sprite;
			var graphics:Graphics = _player.graphics;
			graphics.beginFill(0xFF0000);
			graphics.drawCircle(0,0, 10);
			graphics.endFill();
			_player.cacheAsBitmap = true;
			setHalfStage(_player);
			_playerPos = new Point(_player.x, _player.y);
			//_map.regPoint = _playerPos;
		}
		
		private function resizeHandler(event:Event):void
		{
			setPlayerPos(_playerPos.x, _playerPos.y);
			setHalfStage(_aux);
			drawAux(_aux.graphics);
			_aux.refresh();
		}
		private function drawAux(graphic:Graphics):void
		{
			graphic.clear();
			graphic.beginFill(0xFFFFFF,0);
			graphic.lineStyle(9,0x0000FF);
			graphic.drawRect(0,0,stage.stageWidth*FACT, stage.stageHeight*FACT);
			graphic.endFill();
		}
		private function setHalfStage(...args):void
		{
			for each(var e:DisplayObject in args)
			{
				e.x = this.stage.stageWidth/2;
				e.y = this.stage.stageHeight/2;
			}
		}
	}
}